梯形和平行四邊形的差別是,它只有二個邊是平行的,另外二個邊可以是任何角度。以前這個形狀是非常難用CSS做出來,雖然它是一種常見的形狀,尤其用在模仿標籤的樣子。如果不是用background-image
的話,一般會在長方形兩旁用border
仿造出二個三角形。
雖然這個方法省去了用HTTP request去取得圖片,也可以適應不同的寬度,但是卻不是最好的。這樣做不僅浪費了二個偽元素,在樣式修改上也很不方便。舉個例子,要加邊界、背景圖案,或是圓角的話,這個方法就不容易做到。
就是因為傳統的做法是這麼困難,所以一般在網站看到的標籤都不是二側傾斜的,但是真實世界裡卻是如此。有沒有做梯形標籤的好的方法呢?
還記得前面我們用transform
做出平行四邊形,是不是也可以用某一種transform
就做出梯形?
壞消息是,不行。
不過可以這樣思考,想像在三度空間中旋轉一個長方形,以底為軸向外旋轉,這時從原本的視角看,它就像個梯形!因此我們可以用CSS 3D rotation來模擬這個效果。
.tab {
display: inline-block;
padding: .5em 1em;
color: white;
background: #840715;
transform: perspective(.5em) rotateX(5deg);
}
(上方是原本的長方形)
我們是得到了一個梯形,但是連裡面的文字也一起變形了。同樣的問題在製作平行四邊形時也遇到過,那時我們用了偽元素製造背景,將transform
用在偽元素上,在這裡我們也如法炮製。
.tab {
display: inline-block;
padding: .5em 1em;
color: white;
position: relative;
}
.tab::before {
content: '';
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
z-index: -1;
background: #840715;
transform: perspective(.5em) rotateX(5deg);
}
很好,我們有了梯形背景,而且文字沒有變形。或許你回想起我們在做平行四邊形時用過巢狀元素,同樣方法也可以在這裡使用嗎?
答案是不行,因為CSS 3D transforms不能像2D transforms那樣用反方向的值取消。
現在有一個問題,我們能發現梯形的底比起原本的長方形的底來得寬,這是因為CSS 3D transforms的軸是位於圖形的中間,所以只要把這條軸線轉移到圖形底部就可以了。
.tab::before {
/* 將變形的軸設在圖形的底部 */
transform-origin: bottom;
}
這時又發生另一個問題,因為方形向外傾斜,所以從我們的角度看它的高度縮小了,文字的位置沒有變,造成文字和上邊界太靠近。這時你可能覺得加個padding-top
不就解決了,不過這樣做的話,當瀏覽器不支援3D transforms的時候,我們的標籤在比例上就會很怪異。
(不支援3D transforms時我們的標籤多出了沒有用的padding)
比較好的方法是用scale()
,讓標籤在有或沒有3D transforms時都好看。經過一番測試,發現將標籤高度放大130%是最合適的。
.tab::before {
transform: scaleY(1.3) perspective(.5em) rotateX(5deg);
}
(使用scale()
即使在沒有3D transforms情況下,看起來不算太糟)
這下子你可以看到我們的梯形幾乎和最早用border
方式做的一樣,而且它的語法更加簡明扼要。更棒的是,當我們要為標籤加上樣式時,更能感受到這個方法的威力。
<nav>
<a href="#">OS 1</a>
<a href="#" class="selected">OS 2</a>
<a href="#">OS 3</a>
</nav>
<div class="content">Content</div>
.content {
padding: 1em;
background: white;
border: .1em solid rgba(0,0,0,.4);
border-radius: 2px;
margin-bottom: 2em;
}
nav {
z-index: 1;
padding-left: 1em;
}
nav > a {
display: inline-block;
padding: .3em 1em 0;
text-decoration: none;
color: black;
position: relative;
margin: 0 -.3em;
}
nav > a::before {
content: '';
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
z-index: -1;
background: #ccc;
background-image: linear-gradient(
hsla(0,0%,100%,.6),
hsla(0,0%,100%,0)
);
border: .1em solid rgba(0,0,0,.4);
border-bottom: none;
border-radius: .5em .5em 0 0;
box-shadow: 0 .15em white inset;
transform: scale(1.1, 1.3) perspective(.5em) rotateX(5deg);
transform-origin: bottom;
}
.selected {
z-index: 2;
}
.selected::before {
background: white;
margin-bottom: -.08em;
}
在這裡我們給標籤加上了background
, border
, border-radius
和box-shadow
,更棒的是,當我們想要改變標籤傾斜的方向,只要變更tranform-origin
為bottom left
或bottom right
就可以了。
雖然好用,但這個方法有一個缺點,就是梯形斜邊的角度取決於元素的寬度,也就是說當寬度愈長,斜邊的角度會愈銳利。所以在處理寬度不一樣的標籤時,要讓梯形角度都一樣是很困難的。不過在應付寬度差異不大的標籤時-例如一個導覽例,角度的差距其實很難察覺得出來。